#!/bin/bash
# A (hacky) script for generating API reviews usage:
# ./doApiReview.sh oldVersionTag newVersionTag gerritUserName email name
# Example: ./doApiReview.sh v6.2.3 v6.3.0-alpha1 example.user example.user@qt.io "Example User"

# WARNING: This script runs rm -rf quite a lot, best run it in a separate jail where it can only wreck its immediate environment

set -e

QT_GIT_REPO=https://code.qt.io/qt/qt5.git

BASE_MODULES=(qtshadertools qtdeclarative)
API_REVIEWS_FOR=(qtsensors qtpositioning qtwebchannel qtscxml qtcharts qt3d qtquick3d qtwayland qtwebengine)

checkout_qt_version() {
   mod_list=$(printf ",%s" "${API_REVIEWS_FOR[@]}")
   mod_list=${mod_list:1}

   if [ -d "$1" ]; then
      echo "'$1' already exists, skipping"
      return 0
   fi

   mkdir $1 && cd $1
   git clone $QT_GIT_REPO src
   cd src
   git checkout $1
   perl init-repository --module-subset=qtbase,qtdeclarative,qtshadertools,$mod_list --codereview-username=$2
   cd ../..
   return 0 || return 1
}

build_qt_version() {
   cd "$1"

   found_all=1
   for module in "${BASE_MODULES[@]}"; do
      if [ ! -d "build/$module" ]; then
          echo "Didn't find base module $module in $1"
          found_all=0
          break
      fi
   done

   for module in "${API_REVIEWS_FOR[@]}"; do
      if [ ! -d "build/$module" ]; then
          echo "Didn't find $module in $1"
          found_all=0
          break
      fi
      if [ ! -d "$module-qml" ]; then
          echo "Didn't find $module in $1"
          found_all=0
          break
      fi
   done

   if [ $found_all -eq 1 ]; then
      echo "All modules are built, skipping"
      cd ..
      return
   fi

   rm -rf build install base-install base-build *-qml && mkdir build && cd build
   mkdir qtbase && cd qtbase
   ../../src/qtbase/configure -release -opensource -confirm-license -prefix ../../install
   ninja install
   cd ..
   for module in "${BASE_MODULES[@]}"; do
      mkdir $module
      cd $module
      ../../install/bin/qt-configure-module $(pwd)/../../src/$module
      ninja install
      cd ..
   done
   cp -r ../install ../base-install && cp -r ../build ../base-build
   for module in "${API_REVIEWS_FOR[@]}"; do
      rm -rf $(pwd)/../install && cp -r $(pwd)/../base-install $(pwd)/../install && cp -r $(pwd)/../base-build $(pwd)/../build
      mkdir $module
      cd $module
      if [ "$module" == "qt3d" ]; then
     echo "Qt3D"
         $(pwd)/../../install/bin/qt-configure-module $(pwd)/../../src/$module -no-feature-qt3d-assimp
      elif [ "$module" == "qtquick3d" ]; then
     echo "QtQuick3D"
         $(pwd)/../../install/bin/qt-configure-module $(pwd)/../../src/$module -no-feature-quick3d-assimp
      else
         $(pwd)/../../install/bin/qt-configure-module $(pwd)/../../src/$module
      fi
      ninja install
      cd ..
      cp -r $(pwd)/../install/qml $(pwd)/../$module-qml
   done
   cd ../..
   echo $(pwd)
}

function do_review() {
     old=$1
     new=$2

     username=$3
     email=$4
     name=$5
     module=$6

     cd "$module"
     gitdir=$(git rev-parse --git-dir);

     # Download and install the gerrit pre-commit hook if it isn't already present
     # Ideally this should be cached somewhere so we don't prompt every time
     if [[ ! -f "$gitdir/hooks/commit-msg" ]]; then
        scp -p -P 29418 $username@codereview.qt-project.org:hooks/commit-msg ${gitdir}/hooks/
     fi

     # Configure git
     git config user.email "$email"
     git config user.name "$name"

     # Discard all unstaged changes
     git reset --hard HEAD

     # Reset to the latest dev commit
     git checkout dev

     # Remove any previous API review branch if present and replace it with a new one
     git branch -D api_review_$1_$2 || true
     git checkout -b api_review_$1_$2

     # Nuke any left-overs from a previous review attempt and recreate the directory
     rm -rf $(pwd)/qml-api-review || true
     mkdir $(pwd)/qml-api-review

     if [[ "$module" == "qtdeclarative" ]]; then
        # base-install = qtdeclarative, so just copy that over.
        cp -r $(pwd)/../../../$old/base-install/qml/* $(pwd)/qml-api-review
     else
        cp -r $(pwd)/../../../$old/$module-qml/* $(pwd)/qml-api-review
        base_path=$(pwd)/../../../$old/base-install/qml

        # Remove all files that are also present in the old base install, they should not be reviewed
        cd qml-api-review; rm -rf $(cd $base_path && find . ! -path .); cd ..
     fi

     # Strip away binary artifacts
     find $(pwd)/qml-api-review \( -name '*.dylib' -o -name '*.dll' -o -name '*.so' -o -name '*.png' \) -delete

     qml_files=$(find $(pwd)/qml-api-review -type f -name '*.qml')
     if [[ $qml_files ]]; then
        perl -pe 'BEGIN { undef $/; }; s#(^/\*.*?\*/)(\r?\n)*?##ims' -i $qml_files
     fi

     # Commit API Review base commit
     git add $(pwd)/qml-api-review
     git commit -m "WIP: [Ignore] [QML Directory Base] $module $2 QML API Review" -m "This is a $old baseline commit for reviewing $new, please ignore. It has been auto-generated by doApiReview.sh"

     if [ "$module" == "qtdeclarative" ]; then
        # base-install = qtdeclarative, so just copy that over.
        cp -r $(pwd)/../../../$new/base-install/qml/* $(pwd)/qml-api-review
     else
        cp -r $(pwd)/../../../$new/$module-qml/* $(pwd)/qml-api-review
        base_path=$(pwd)/../../../$new/base-install/qml

        # Remove all files that are also present in the old base install, they should not be reviewed
        cd qml-api-review; rm -rf $(cd $base_path && find . ! -path .); cd ..
     fi

     # Strip away binary artifacts
     find $(pwd)/qml-api-review \( -name '*.dylib' -o -name '*.dll' -o -name '*.so' -o -name '*.png' \) -delete

     # Placeholder file in case we don't have any actual changes to commit
     echo "Review file. If this is the only file then there are no changes for this module." > $(pwd)/qml-api-review/REVIEW-FILE

     qml_files=$(find $(pwd)/qml-api-review/ -type f -name '*.qml')
     if [[ $qml_files ]]; then
        perl -pe 'BEGIN { undef $/; }; s#(^/\*.*?\*/)(\r?\n)*?##ims' -i $qml_files
     fi

     # Commit API Review
     git add $(pwd)/qml-api-review
     git commit -m "WIP: $module $new QML API Review" -m "This is a commit for reviewing the QML API of $module $new. It has been auto-generated by doApiReview.sh"
     cd ..
}

function create_reviews() {
   cd $(pwd)/dev/src
   do_review "$1" "$2" "$3" "$4" "$5" "qtdeclarative"

   for module in "${API_REVIEWS_FOR[@]}"; do
     do_review "$1" "$2" "$3" "$4" "$5" "$module"
   done

   cd ../..
}

STEPS=3

OLD_VERSION=$1
NEW_VERSION=$2
CODEREVIEW_USERNAME=$3
EMAIL=$4
NAME=$5

echo "Reviewing $1 vs $2"

echo "[1/$STEPS] Preparing repositories..."
checkout_qt_version "$OLD_VERSION" "$CODEREVIEW_USERNAME"
checkout_qt_version "$NEW_VERSION" "$CODEREVIEW_USERNAME"
checkout_qt_version "dev" "$CODEREVIEW_USERNAME"
echo "[2/$STEPS] Building modules..."
build_qt_version "$OLD_VERSION"
build_qt_version "$NEW_VERSION"
echo "[3/$STEPS] Creating reviews..."
create_reviews "$OLD_VERSION" "$NEW_VERSION" "$CODEREVIEW_USERNAME" "$EMAIL" "$NAME"
echo "You can now find all the generated reviews in dev/src/MODULE_NAME. Please review them manually before pushing them to gerrit."
